﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace WFWS.Core
{
    public abstract class HttpListenerBase
    {
        private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
        private HttpRequestHandlerFactory _handlerFactory = new HttpRequestHandlerFactory();
        private TcpListener _listener;
        private HttpServer _server;
        private bool _shutdown;
        private int _port;
        private int _pendingAccepts;
        protected abstract bool OnAcceptingSocket(Socket socket);
        private Action<Socket> _executor;

        public HttpListenerBase(int port, HttpServer server,Action<Socket> executor)
        {
            _port = port;
            _server = server;
            _executor = executor;
        }

        public void Start(int backlog)
        {
            _listener = new TcpListener(_port);
            _listener.Start(backlog);
            Interlocked.Increment(ref _pendingAccepts);
            _listener.BeginAcceptSocket(OnAccept, null);
        }

        public void Stop()
        {
            _shutdown = true;
            _listener.Stop();
            //if(_shutdownEvent.WaitOne())
            _listener = null;
        }

        private void OnAccept(IAsyncResult ar)
        {
        	bool beginAcceptCalled = false;//flag for retry
            try
            {
                int count = Interlocked.Decrement(ref _pendingAccepts);
                //for safe stop //almost useless...
                if (_shutdown)
                {
                    if (count == 0)
                    {
                        _shutdownEvent.Set();
                        return;
                    }
                }

                Interlocked.Increment(ref _pendingAccepts);
                _listener.BeginAcceptSocket(OnAccept, null);
                beginAcceptCalled = true;
                Socket socket = _listener.EndAcceptSocket(ar);
                if (!OnAcceptingSocket(socket))
                {
                    socket.Disconnect(true);
                    return;
                }

                _executor(socket);
                //_server.Execute(socket);
            }
            catch (Exception err)
            {
                if (!beginAcceptCalled)
                    RetryBeginAccept();
            }
        }

        private void RetryBeginAccept()
        {
            try
            {
                _listener.BeginAcceptSocket(OnAccept, null);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
